// $Id: result.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2008-2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPCOM_RESULT_HPP
#define XPCOM_RESULT_HPP

#include <xpcom/config.hpp>
#ifndef XPCOM_NO_IOSTREAM
#include <iosfwd>
#endif // XPCOM_NO_IOSTREAM
#include <xpcom/types.hpp>

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

namespace xpcom {

//
// XPCOM result manipulations class.
//
// A result value can be any value, but typically, it is constructed from three
// parts: severity, module, and code.  Each part is a 16-bit value.
//
class XPCOM_DECL result
{
public:
    // These flags identifies the level of warning
    enum severity_tag
    {
        severity_success = 0,
        severity_error = 1
    };

    result() throw() :
        val_(0)
    {
    }

    result(const result& rhs) throw() :
        val_(rhs.val_)
    {
    }

    result(result_t val) throw() :
        val_(val)
    {
    }

    result(uint16_t severity, uint16_t module, uint16_t code) throw();

    result& operator=(const result& rhs) throw()
    {
        val_ = rhs.val_;
        return *this;
    }

    result& operator=(result_t val) throw()
    {
        val_ = val;
        return *this;
    }

    operator result_t() const throw()
    {
        return val_;
    }

    operator result_t&() throw()
    {
        return val_;
    }

    bool is_ok() const throw()
    {
        return XPCOM_LIKELY(val_ == 0);
    }

    bool succeeded() const throw()
    {
        return XPCOM_LIKELY(!(val_ & 0x80000000));
    }

    bool failed() const throw()
    {
        return XPCOM_UNLIKELY(val_ & 0x80000000);
    }

    result_t get() const throw()
    {
        return val_;
    }

    uint16_t severity() const throw();
    uint16_t module() const throw();
    uint16_t code() const throw();

    void swap(result& rhs) throw();

    template <typename CharT>
    void to_str(basic_string<CharT>& str) const;

    string str() const;
    wstring wstr() const;

private:
    result_t val_;
};

// swap
inline void swap(result& lhs, result& rhs)
{
    lhs.swap(rhs);
}

// IO
#ifndef XPCOM_NO_IOSTREAM

template <typename CharT, typename Traits>
inline std::basic_ostream<CharT, Traits>& operator<<(
        std::basic_ostream<CharT, Traits>& os, const result& rhs)
{
    basic_string<CharT> s;
    rhs.to_str(s);
    return os << s;
}

#endif // XPCOM_NO_IOSTREAM

} // namespace xpcom

//
// Result algorithms
//
#define XPCOM_RESULT_MODULE_BASE_OFFSET 0x45

#define XPCOM_MAKE_RESULT(severity, module, code) \
    static_cast< ::xpcom::result_t>( \
        ((static_cast< ::xpcom::uint32_t>(severity)) << 31) | \
        ((static_cast< ::xpcom::uint32_t>((module) + XPCOM_RESULT_MODULE_BASE_OFFSET)) << 16) | \
        (static_cast< ::xpcom::uint32_t>(code)) \
        )

#define XPCOM_RESULT_SEVERITY(r) \
    static_cast< ::xpcom::uint16_t>(((r) >> 31) & 0x1)

#define XPCOM_RESULT_MODULE(r) \
    static_cast< ::xpcom::uint16_t>((((r) >> 16) - XPCOM_RESULT_MODULE_BASE_OFFSET) & 0x1FFF)

#define XPCOM_RESULT_CODE(r) \
    static_cast< ::xpcom::uint16_t>((r) & 0xFFFF)

//
// Convenience macros for defining results
//
#define XPCOM_DEFINE_RESULT_MODULE(name, module) \
    const ::xpcom::uint16_t name = (module)

#define XPCOM_DEFINE_RESULT(name, severity, module, code) \
    const ::xpcom::result_t name = \
        XPCOM_MAKE_RESULT(severity, module, code);

#define XPCOM_DEFINE_RESULT_S(name, module, code) \
    XPCOM_DEFINE_RESULT(name, ::xpcom::result::severity_success, module, code)

#define XPCOM_DEFINE_RESULT_E(name, module, code) \
    XPCOM_DEFINE_RESULT(name, ::xpcom::result::severity_error, module, code)

#define XPCOM_DEFINE_RESULT_VALUE(name, value) \
    const ::xpcom::result_t name = static_cast< ::xpcom::result_t>(value)

//
// Standard "it worked" return value
//
XPCOM_DEFINE_RESULT_VALUE(NS_OK, 0);

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // XPCOM_RESULT_HPP
